package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.mapper.UserMapper;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: LXW
 * Date: 2022-08-06
 * Time: 14:40
 */
@Data
public class Room {
    private String roomId;
    // 玩家1
    private User user1;
    // 玩家2
    private User user2;
    // 先手方的用户 id
    private int whiteUserId = 0;
    // 棋盘, 数字 0 表示未落子位置. 数字 1 表示玩家 1 的落子. 数字 2 表示玩家 2 的落子
    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;
    private int[][] chessBoard = new int[MAX_ROW][MAX_COL];

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private RoomManager roomManager;
    @Resource
    private UserMapper userMapper;


    /**
     * 手动获得需要的Bean对象
     */
    public Room() {
        // 使用 uuid 作为唯一身份标识
        roomId = UUID.randomUUID().toString();

        onlineUserManager = JavaGobangApplication.ac.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.ac.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.ac.getBean(UserMapper.class);

        System.out.println("create Room: " + roomId + ", roomManager: " + roomManager);
    }


    /**
     * 实现落子操作
     * @param message
     * @throws IOException
     */
    public void putChess(String message) throws IOException {
        GameRequest req = objectMapper.readValue(message, GameRequest.class);
        GameResponse response = new GameResponse();
        // 1. 进行落子
        int chess = req.getUserId() == user1.getUserId() ? 1 : 2;
        int row = req.getRow();
        int col = req.getCol();
        if (chessBoard[row][col] != 0) {
            System.out.println("落子位置有误! " + req);
            return;
        }
        chessBoard[row][col] = chess;
        printChessBoard();
        // 2. 检查游戏结束
        //    返回的 winner 为玩家的 userId
        int winner = checkWinner(chess, row, col);
        // 3. 把响应写回给玩家
        response.setMessage("putChess");
        response.setUserId(req.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);
        WebSocketSession session1 = onlineUserManager.getSessionFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getSessionFromGameRoom(user2.getUserId());
        if (session1 == null) {
            // 玩家1 掉线, 直接认为玩家2 获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线!");
        }
        if (session2 == null) {
            // 玩家2 掉线, 直接认为玩家1 获胜
            response.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线!");
        }
        String responseJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(responseJson));
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(responseJson));
        }
        // 4. 如果玩家胜负已分, 就把 room 从管理器中销毁
        if (response.getWinner() != 0) {
            userMapper.userWin(response.getWinner() == user1.getUserId() ? user1.getUserId() : user2.getUserId());
            userMapper.userLose(response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId());
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
            System.out.println("游戏结束, 房间已经销毁! roomId: " + roomId + " 获胜方为: " + response.getWinner());
        }
    }


    /**
     * 打印棋盘信息，方便后期调试
     */
    private void printChessBoard() {
        System.out.println("打印棋盘信息: ");
        System.out.println("===========================");
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < MAX_COL; c++) {
                System.out.print(chessBoard[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("===========================");
    }


    /**
     * 判定胜负
     * @param chess chess等于1代表玩家1的落子 等于2代表玩家2的落子
     * @param row 行
     * @param col 列
     * @return 返回胜者的id 返回0说明胜负未分
     */
    private int checkWinner(int chess, int row, int col) {
        // 以 row, col 为中心
        boolean done = false;
        // 1. 检查所有的行(循环五次)
        for (int c = col - 4; c <= col; c++) {
            if (c < 0 || c >= MAX_COL) {
                continue;
            }
            if (chessBoard[row][c] == chess
                    && chessBoard[row][c + 1] == chess
                    && chessBoard[row][c + 2] == chess
                    && chessBoard[row][c + 3] == chess
                    && chessBoard[row][c + 4] == chess) {
                done = true;
            }
        }
        // 2. 检查所有的列(循环五次)
        for (int r = row - 4; r <= row; r++) {
            if (r < 0 || r >= MAX_ROW) {
                continue;
            }
            if (chessBoard[r][col] == chess
                    && chessBoard[r + 1][col] == chess
                    && chessBoard[r + 2][col] == chess
                    && chessBoard[r + 3][col] == chess
                    && chessBoard[r + 4][col] == chess) {
                done = true;
            }
        }
        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
                continue;
            }
            if (chessBoard[r][c] == chess
                    && chessBoard[r + 1][c + 1] == chess
                    && chessBoard[r + 2][c + 2] == chess
                    && chessBoard[r + 3][c + 3] == chess
                    && chessBoard[r + 4][c + 4] == chess) {
                done = true;
            }
        }
        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
                continue;
            }
            if (chessBoard[r][c] == chess
                    && chessBoard[r + 1][c - 1] == chess
                    && chessBoard[r + 2][c - 2] == chess
                    && chessBoard[r + 3][c - 3] == chess
                    && chessBoard[r + 4][c - 4] == chess) {
                done = true;
            }
        }
        if (!done) {
            return 0;
        }
        return chess == 1 ? user1.getUserId() : user2.getUserId();
    }
}
